﻿using System;
using System.Collections.Generic;
using System.Text;

using RaisingStudio.Data;
using RaisingStudio.Data.Common.Configuration;
using RaisingStudio.Data.Common.Managers;
using RaisingStudio.Common.Xml;

namespace RaisingStudio.Data.Common.Factories
{
    /// <summary>
    /// database factory
    /// </summary>
    public class ConnectionFactory
    {
        /// <summary>
        /// connection config file name.
        /// </summary>
        public static readonly string CONNECTIONSETTINGSFILENAME = "connections.config";
    
        protected static Dictionary<string, ConnectionSetting> connectionSettings = new Dictionary<string, ConnectionSetting>();

        public const string CONNECTIONNAME = "name";
        public const string DATABASETYPE = "databaseType";
        public const string PROVIDERNAME = "providerName";

        /// <summary>
        /// static Constructor
        /// </summary>
        static ConnectionFactory()
        {
            // read connecting setting.
            /*
            string baseDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
            string fileName = Path.Combine(baseDirectory, ConnectionSettingsFileName);
            System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
            xmlDocument.Load(fileName);
             */
            // use Resources lib.
            System.Xml.XmlDocument xmlDocument = Resources.GetConfigAsXmlDocument(CONNECTIONSETTINGSFILENAME);
            AddConnectionSettings(xmlDocument);
        }


        private static object connectionSettings_lock = new object();

        public static void AppendConnectionSettings(string baseDirectory)
        {
            System.Xml.XmlDocument xmlDocument = Resources.GetConfigAsXmlDocument(baseDirectory, CONNECTIONSETTINGSFILENAME);
            lock (connectionSettings_lock)
            {
                AddConnectionSettings(xmlDocument);
            }
        }

        private static void AddConnectionSettings(System.Xml.XmlDocument xmlDocument)
        {
            if ((xmlDocument != null) && (xmlDocument.DocumentElement != null))
            {
                System.Xml.XmlElement xmlElement = xmlDocument.DocumentElement;
                foreach (System.Xml.XmlNode childXmlNode in xmlElement)
                {
                    if (childXmlNode is System.Xml.XmlElement)
                    {
                        System.Xml.XmlElement childXmlElement = childXmlNode as System.Xml.XmlElement;
                        ConnectionSetting connectionSetting = new ConnectionSetting();
                        if (childXmlElement.Attributes[CONNECTIONNAME] != null)
                        {
                            connectionSetting.ConnectionName = childXmlElement.Attributes[CONNECTIONNAME].Value;
                        }
                        if (childXmlElement.Attributes[DATABASETYPE] != null)
                        {
                            connectionSetting.DatabaseType = ParseDatabaseType(childXmlElement);
                        }
                        if (childXmlElement.Attributes[PROVIDERNAME] != null)
                        {
                            connectionSetting.ProviderName = childXmlElement.Attributes[PROVIDERNAME].Value;
                        }
                        connectionSetting.ConnectionString = childXmlElement.InnerText;

                        connectionSettings.Add(connectionSetting.ConnectionName, connectionSetting);
                    }
                }
            }
        }

        private static DatabaseType ParseDatabaseType(System.Xml.XmlElement childXmlElement)
        {
            return (DatabaseType)System.Enum.Parse(typeof(DatabaseType), childXmlElement.Attributes[DATABASETYPE].Value, false);
        }

        /// <summary>
        /// Create database connection.
        /// </summary>
        /// <returns>database connection.</returns>
        public static System.Data.IDbConnection CreateConnection()
        {
            return CreateConnection(string.Empty);
        }

        /// <summary>
        /// Create database connection.
        /// </summary>
        /// <param name="connectionName">the name of connection.</param>
        /// <returns>database connection.</returns>
        public static System.Data.IDbConnection CreateConnection(string connectionName)
        {
            ConnectionSetting connectionSetting = null;
            lock (connectionSettings_lock)
            {
                connectionSetting = connectionSettings[connectionName];
            }
            if (connectionSetting != null)
            {
                if (connectionSetting.DatabaseType != DatabaseType.OTHER)
                {
                    return CreateConnection(connectionSetting.DatabaseType, connectionSetting.ConnectionString);
                }
                else
                {
                    return CreateConnection(connectionSetting.ProviderName, connectionSetting.ConnectionString);
                }
            }
            else
            {
                // TODO: exception.
                return null;
            }
        }

        public static void GetConnectionSetting(out DatabaseType databaseType, out string providerName)
        {
            GetConnectionSetting(string.Empty, out databaseType, out providerName);
        }

        public static void GetConnectionSetting(string connectionName, out DatabaseType databaseType, out string providerName)
        {
            databaseType = DatabaseType.OTHER;
            providerName = null;
            ConnectionSetting connectionSetting = null;
            lock (connectionSettings_lock)
            {
                connectionSetting = connectionSettings[connectionName];
            }
            if (connectionSetting != null)
            {
                databaseType = connectionSetting.DatabaseType;
                providerName = connectionSetting.ProviderName;
            }
        }

        /// <summary>
        /// Create database connection.
        /// </summary>
        /// <param name="databaseType">database type.</param>
        /// <param name="connectionString">connection string.</param>
        /// <returns>database connection.</returns>
        public static System.Data.IDbConnection CreateConnection(DatabaseType databaseType, string connectionString)
        {
            switch (databaseType)
            {
                case DatabaseType.SQL:
                    {
                        return new System.Data.SqlClient.SqlConnection(connectionString);
                    }
                case DatabaseType.SQLCE:
                    {
                        return new System.Data.SqlServerCe.SqlCeConnection(connectionString);
                    }
                case DatabaseType.ORACLE:
                    {
                        return new System.Data.OracleClient.OracleConnection(connectionString);
                    }
                case DatabaseType.ODBC:
                    {
                        return new System.Data.Odbc.OdbcConnection(connectionString);
                    }
                case DatabaseType.OLEDB:
                    {
                        return new System.Data.OleDb.OleDbConnection(connectionString);
                    }
                case DatabaseType.SHAREPOINT:
                    {
                        return new System.Data.SharePoint.SharePointConnection(connectionString);
                    }
                default:
                    {
                        throw (new System.NotSupportedException("Unknown Type."));
                    }
            }
        }

        /// <summary>
        /// Create database connection.
        /// </summary>
        /// <param name="providerName">Provider name.</param>
        /// <param name="connectionString">Connection string.</param>
        /// <returns>A database connection.</returns>
        public static System.Data.IDbConnection CreateConnection(string providerName, string connectionString)
        {
            return ProviderManager.Instance.CreateConnection(providerName, connectionString);
        }

        /// <summary>
        /// Gets database type.
        /// </summary>
        /// <param name="connection">database connection.</param>
        /// <returns>database type.</returns>
        public static DatabaseType GetDatabaseType(System.Data.IDbConnection connection)
        {
            if (connection is System.Data.SqlClient.SqlConnection)
            {
                return DatabaseType.SQL;
            }
            else if (connection is System.Data.SqlServerCe.SqlCeConnection)
            {
                return DatabaseType.SQLCE;
            }
            else if (connection is System.Data.OracleClient.OracleConnection)
            {
                return DatabaseType.ORACLE;
            }
            else if (connection is System.Data.Odbc.OdbcConnection)
            {
                return DatabaseType.ODBC;
            }
            else if (connection is System.Data.OleDb.OleDbConnection)
            {
                return DatabaseType.OLEDB;
            }
            else if (connection is System.Data.SharePoint.SharePointConnection)
            {
                return DatabaseType.SHAREPOINT;
            }
            else
            {
                throw (new System.NotSupportedException("Unknown Type."));
            }
        }
    }
}
